/*
Context 是一个接口类型，所有的Context 构成一颗代表上下文的树形结构。
Context 通过一个Context值产生出任意个子值。这些子值可以携带其父值的属性和数据，
也可以响应我们通过其父值传达的信号。
Context 是并发安全的。
这棵树的树根（或者称上下文根节点）是一个已经在context包中预定义好的Context值，
它是全局唯一的。通过调用context.Background函数获取它,
它既不可以被撤销（cancel），也不能携带任何数据.
CTX.Value是向上寻值并返回，不会向下及同级寻值。
*/
package main

import (
	goroutine "Ljohn/contextTest/goroutineLeak"
	"context"
	"fmt"
	"math/rand"
	"runtime"
	"time"
)

func main() {
	//goroutine.GoroutineLeak()
	defer func() {
		time.Sleep(1 * time.Second)
		fmt.Println("current goroutines:", runtime.NumGoroutine())
	}()
	goroutine.GoroutineLeak()
	fmt.Println("???")

	//TestCtxGround()
	/*	c := make(chan struct{}, 1)
		execWork(c)
		<-c*/
}

func execWork(c chan<- struct{}) {
	ctx := context.Background()
	ctx, _ = context.WithTimeout(ctx, 3*time.Second)
	go func() {
		<-ctx.Done()
		fmt.Println("超时了")
		c <- struct{}{}
	}()
	go func() {
		i := work()
		fmt.Println("value", i)
	}()
}

func work() int64 {
	rand.Seed(time.Now().UnixNano())
	x := rand.Int63n(15)
	fmt.Println("work executing..", time.Now())
	time.Sleep(time.Duration(x) * time.Second)
	fmt.Println("work exec end..", time.Now())
	return x
}

func TestCtxGround() {
	ctx := context.Background()
	fmt.Printf("%p\n", ctx)
	fmt.Printf("%v\n", ctx)
	ctxV := context.WithValue(ctx, "t", "ttt")
	c := context.Background()
	fmt.Printf("%p\n", ctxV)
	fmt.Printf("%v\n", ctxV)

	fmt.Println("我自己是无值的，也不会向下去寻值:", c.Value("t"))
	canfunc := tt1(ctxV)
	go func() {
		start := time.Now()
		fmt.Println("正常执行，我需要等5S", start)
		time.Sleep(time.Second * 5)
		canfunc()
		fmt.Println("正常执行，我需要等5S", time.Now(), " 有五秒吗？", time.Now().Sub(start))
		fmt.Println("向下ctx取消函数也没我啥事：", ctx.Err())
	}()
	go func() {
		<-ctxV.Done()
		fmt.Println("我应该不会被结束的")
	}()
	//<-ctx.Done() //没有人可以通知他的事件
	fmt.Println("我自己是无值的，也不会向下去寻值:", ctx.Value("t"))
}

func tt1(ctx context.Context) context.CancelFunc {
	ctx1, funcC := context.WithCancel(ctx)
	go func() {
		s := <-ctx1.Done() //S 只是一个空结构体，用来通信
		fmt.Println("我是CTX1 收到信号:", s, ctx1.Err())
	}()
	ctx2 := context.WithValue(ctx1, "t", "test")
	fmt.Println("Ctx2 开始读值：", ctx2.Value("t"))
	fmt.Println("Ctx1 开始读值：,Ctx1本身无值，向上查询"+
		"", ctx1.Value("t"))
	go func() {
		s := <-ctx2.Done()
		fmt.Println("我是CTX2 收到信号:", s, ctx2.Err())
	}()
	tt2(ctx2)
	tt3(ctx2)
	return funcC
}

func tt2(ctx context.Context) {
	dCtx, cFunc := context.WithDeadline(ctx, time.Now().Add(time.Second*3))
	//d, ok := dCtx.Deadline()
	go func() {
		s := <-dCtx.Done()
		fmt.Println("我是到期时间CTX 收到信号:", s, dCtx.Err())
	}()
	go func() {
		time.Sleep(time.Second * 10)
		cFunc()
	}()
}

func tt3(ctx context.Context) {
	tCtx, _ := context.WithTimeout(ctx, 1*time.Second)
	go func() {
		s := <-tCtx.Done()
		fmt.Println("我是时间CTX 收到信号:", s, tCtx.Err())
	}()
}

func TestCtxWithCancel() {
	ctx, cancel := context.WithCancel(context.Background())
	go func() {
		defer func() {
			cancel()
		}()
		time.Sleep(time.Second * 5)
	}()
	ctx.Done()
	fmt.Println("结束了")

}
